package Command;

import java.util.Stack;
import java.util.Vector;

import DTO.Field;
import DTO.Row;
import DTO.Table;
import XML.XMLHelper;
public class Condition {
	
	/**
	 * Check if string parameter "may be" condition. It not exactly so its name is mayBe.
	 * This method support for condition in "where" statement.
	 * This will check number of quote, if it %2 !0 , return false.
	 * Then check operator is "=="
	 * @param str String to be checked
	 * @return 
	 * True : if it may be condition.
	 * False : if not! 
	 */
	public static boolean mayBeCondition(String str)
	{
		boolean ret = false;
		String trim = str.trim();		
		Vector<Integer> quoteIndices = Command.countSingleQuote(trim);
		
		if(quoteIndices.size() % 2 != 0)
		{
			return false;
		}
		
		if(trim.contains("=="))
		{
			boolean safeEqual = safeCompareOperator(trim, quoteIndices, "==");
			
			if(safeEqual == true)
				return false;					
		}
		
		
		int firstOperatorIndex = Integer.MAX_VALUE;
		String firstOperator = "";
		for(int i = 0 ; i < Command.compareOperator.length; i++)
		{
			int index;
			if( (index = trim.indexOf(Command.compareOperator[i])) > -1
					&& safeCompareOperator(trim, quoteIndices, Command.compareOperator[i]) == true)
			{
				if (firstOperatorIndex > index + 1)
				{
					firstOperatorIndex = index;
					firstOperator = Command.compareOperator[i];					
				}
			}
		}
		
		if(!firstOperator.equals(""))
		{
			String left = trim.substring(0, firstOperatorIndex);			
			String right = trim.substring(firstOperatorIndex + firstOperator.length());
			if(right != null && left != null && right.length() > 0 && left.length() > 0)
			{
				ret = true;
			}
		}
		
		return ret;
	}
	
	public static String[] getOperandsAndOperator(String str)
	{
		String[] ret = null;
		String trim = str.trim();
		Vector<Integer> quoteIndices = Command.countSingleQuote(trim);
		
		if(quoteIndices.size() % 2 != 0)
		{
			return null;
		}
		
		if(trim.contains("=="))
		{
			boolean safeEqual = safeCompareOperator(trim, quoteIndices, "==");
			
			if(safeEqual == false)
				return null;					
		}
		
		int firstOperatorIndex = Integer.MAX_VALUE;
		String firstOperator = "";
		for(int i = 0 ; i < Command.compareOperator.length; i++)
		{
			int index;
			if( (index = trim.indexOf(Command.compareOperator[i])) > -1
					&& safeCompareOperator(trim, quoteIndices, Command.compareOperator[i]) == true)
			{
				if (firstOperatorIndex > index + 1)
				{
					firstOperatorIndex = index;
					firstOperator = Command.compareOperator[i];					
				}
			}
		}
		
		if(!firstOperator.equals(""))
		{
			String left = trim.substring(0, firstOperatorIndex);
			String right = trim.substring(firstOperatorIndex + firstOperator.length());
			if(right != null && left != null && right.length() > 0 && left.length() > 0)
			{
				ret = new String[3];
				ret[0] = left;
				ret[0] = left.replaceAll(" +$", "");
				ret[1] = firstOperator;
				ret[2] = right.trim();
			}
		}
		
		return ret;
	}

	private static boolean safeCompareOperator(String trim,
			Vector<Integer> quoteIndices,
			String compareOperator) {
		int equalIndex = trim.indexOf(compareOperator);
		boolean safeEqual = true;
		for(int i = 0 ; i < quoteIndices.size(); i+=2)
		{
			if(quoteIndices.get(i) < equalIndex
					&& quoteIndices.get(i+1) > equalIndex)
			{
				safeEqual = false;
			}
			
		}
		return safeEqual;
	}
	
	public static boolean checkParentheses(String str)
	{
		boolean ret = false;
		int nOpen = 0;
		int nClose = 0;
		for(int i = 0 ; i < str.length(); i++)
		{
			if(str.charAt(i) == '(')
			{
				nOpen++;
			}
			else if (str.charAt(i) == ')')
			{
				nClose++;
			}
		}
		
		if(nOpen == nClose)
			ret = true;
		
		return ret;
	}
	
	public static Vector<Row> ReversePoland(String str, String dbName, Table table)
	{
		Vector<Field> fields = table.get_Fields();	
		Vector<Row> rows = table.get_Rows();
		return mainInReversePoland(str, dbName, fields, rows);
	}
	
	public static Vector<Row> ReversePoland(String str, String dbName,  String tableName)
	{		
		Vector<Field> fields = XMLHelper.GetListOfField(dbName, tableName);		
		Vector<Row> rows = XMLHelper.GetListOfRow(dbName, tableName);	
		return mainInReversePoland(str, dbName, fields, rows);
	}

	private static Vector<Row> mainInReversePoland(String str, String dbName,
			Vector<Field> fields, Vector<Row> rows) {
		Stack<Object> poland = new Stack<Object>();
		Vector<Row> filterRow = null;		
		// Begin		
		
		while(str != null)
		{
			while(str.trim().startsWith("("))
			{
				System.out.println("put (");
				poland.push("(");
				str = str.trim().substring(1);
			}
			
			String[] strs = getOperandsAndOperator(str);
						
			if(strs != null)
			{
				String[] strs2;
				
				if(strs[2].trim().startsWith("\'")){
					int openSingle = strs[2].trim().indexOf("\'");
					String rightTemp = strs[2].substring(openSingle + 1);
					int closeSingle = rightTemp.trim().indexOf("\'");
					rightTemp = rightTemp.substring(0, closeSingle);
					strs2 = new String[2];
					strs2[0] = rightTemp;
					int afterIndex = strs[2].indexOf(rightTemp) + rightTemp.length();					
					strs2[1] = strs[2].substring(afterIndex + 1);
					System.out.println("after strs2[1] " + strs2[1]);
					str = strs2[1];
				}
				else
					strs2 = strs[2].split(" ", 2);
				
				int nCloseparentheses = 0;
				boolean isPushAnd = false;
				boolean isPushOr = false;
				
				while(strs2[0].contains(")"))
				{				
					int closeParentheses = strs2[0].lastIndexOf(")");
					strs2[0] = strs2[0].substring(0, closeParentheses);
					nCloseparentheses++;
				}		
				
				if(strs2.length > 1)
				{												
					while(strs2[1].trim().startsWith((")")))
					{
						strs2[1] = strs2[1].trim().substring(1);
						nCloseparentheses++;
					}
					
					if (strs2[1].trim().startsWith("and"))
					{
						isPushAnd = true;
						str = strs2[1].trim().substring(3);
					}
					else if (strs2[1].startsWith("or"))
					{
						isPushOr = true;
						str = strs2[1].trim().substring(2);
					}
					else
					{
						str = null;
					}
				}
				else
				{
					str = null;
				}
				
				addExpressionToPoland(fields, rows, poland, strs[0], strs[1], strs2[0]);				
				
				for(int j = 0 ; j < nCloseparentheses; j++)
				{					
					System.out.println("put )");
					addExpressionToPoland(fields, rows, poland, ")", null, null);	
				}
				
				if(isPushAnd)
				{
					System.out.println("put and");
					poland.push("and");
				}
				
				if(isPushOr)
				{
					System.out.println("put or");
					poland.push("or");
				}
			}
			else
			{
				str = null;
			}
		}				
		
		// End		
		System.out.println("poland size: " + poland.size());		
		if(poland.size() == 1 && poland.peek() instanceof String)
		{
			
			String condition = String.valueOf(poland.pop());
			filterRow = filterRowForOneCondition(fields, rows, condition);
		}
		else if(poland.size() == 1 && !(poland.peek() instanceof String))
		{			
			filterRow = (Vector<Row>) poland.pop();	
		}
				
		return filterRow;
	}
	
	private static void addExpressionToPoland(Vector<Field> fields, Vector<Row> rows, Stack<Object> poland, String leftOperand, String operator, String rightOperand)
	{
		
		// case closing parentheses
		Vector<Row> filterRow = (Vector<Row>) rows.clone();
		if(operator == null && rightOperand == null && leftOperand == ")" && poland.peek() instanceof String)
		{	
			String top = (String) poland.pop();
			System.out.println("pop left of ) : " + top);
			if(Condition.mayBeCondition(top))
			{				
				String rightExp = top;
				String logicOperator = (String) poland.pop();
				String leftExp;
				if(logicOperator == "and")
				{		
					Object popTop = poland.pop();
					if(popTop instanceof String)
					{
						leftExp = String.valueOf(popTop);	
						System.out.println("pop left of and " + leftExp);
						filterRow = filterRowForOneCondition(fields, filterRow, leftExp);
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
					}
					else
					{
						Vector<Row> preRows = (Vector<Row>) popTop;
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
						filterRow = andTwoVectorRow(preRows, filterRow);
					}					

					System.out.println("pop (");
					poland.pop(); // Open parentheses
				}
				else if(logicOperator == "or")
				{
					Object popTop = poland.pop();
					if(popTop instanceof String)
					{
						leftExp = String.valueOf(popTop);	
						System.out.println("pop left of or " + leftExp);
						Vector<Row> cloneRow = (Vector<Row>) filterRow.clone();			
						filterRow = filterRowForOneCondition(fields, filterRow, leftExp);
						cloneRow = filterRowForOneCondition(fields, cloneRow, rightExp);
						filterRow = orTwoVectorRow(filterRow, cloneRow);
					}
					else
					{
						System.out.println("or with old");
						Vector<Row> preRows = (Vector<Row>) popTop;
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
						filterRow = orTwoVectorRow(preRows, filterRow);
					}
					
					System.out.println("pop (");
					poland.pop(); // Open parentheses
				}
				
			}			
		}
		else if (operator == null && rightOperand == null && leftOperand == ")" && !(poland.peek() instanceof String))
		{
			if(poland.size() > 1)
			{
				System.out.println("pop (");
				poland.remove(poland.size() - 2);
			}
		}
		else
		{
			
			if(!isStackHaveOpenParentheses(poland) && poland.size() > 0)
			{
				if(poland.peek() == "and")
				{					
					System.out.println("pop and");
					poland.pop();
					String leftExp;
					String rightExp = leftOperand + " " + operator + " " + rightOperand;
					Object popTop = poland.pop();
					if(popTop instanceof String)
					{
						leftExp = String.valueOf(popTop);	
						System.out.println("pop left of and " + leftExp);
						filterRow = filterRowForOneCondition(fields, filterRow, leftExp);
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
					}
					else
					{
						System.out.println("and with old");
						Vector<Row> preRows = (Vector<Row>) popTop;
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
						filterRow = andTwoVectorRow(preRows, filterRow);
					}
				}
				else if (poland.peek() == "or")
				{
					System.out.println("pop or");
					poland.pop();
					String leftExp;
					String rightExp = leftOperand + " " + operator + " " + rightOperand;
					Object popTop = poland.pop();
					if(popTop instanceof String)
					{
						leftExp = String.valueOf(popTop);	
						System.out.println("pop left of or " + leftExp);
						Vector<Row> cloneRow = (Vector<Row>) filterRow.clone();	
						filterRow = filterRowForOneCondition(fields, filterRow, leftExp);
						cloneRow = filterRowForOneCondition(fields, cloneRow, rightExp);
						filterRow = orTwoVectorRow(filterRow, cloneRow);
					}
					else
					{
						System.out.println("or with old");
						Vector<Row> preRows = (Vector<Row>) popTop;
						filterRow = filterRowForOneCondition(fields, filterRow, rightExp);
						filterRow = orTwoVectorRow(preRows, filterRow);
					}					
				}
			}			
			else
			{				
				System.out.println("put compare " + leftOperand+ " " + operator + " " + rightOperand);
				poland.push(leftOperand + " " + operator + " " + rightOperand);
			}
		}
		
		if(rows.size() != filterRow.size())		
		{			
			if(poland.size() >= 2 && !(poland.get(poland.size() - 2) instanceof String))
			{
				String operatorForOld = (String) poland.pop();
				Vector<Row> oldRow = (Vector<Row>) poland.pop();
				if(operatorForOld == "and")
				{
					System.out.println("And with old");
					filterRow = andTwoVectorRow(filterRow, oldRow);
				}
				else if(operatorForOld == "or")
				{
					System.out.println("Or with old");
					filterRow = orTwoVectorRow(filterRow, oldRow);
				}
			}
			
			System.out.println("Put old");
			poland.push(filterRow);		
		}
	}

	private static boolean isStackHaveOpenParentheses(Stack<Object> poland)
	{
		for(int i = poland.size() - 1; i >= 0; i--)
		{
			if(poland.get(i) == "(")
			{
				return true;
			}
		}
		
		return false;
	}
	
	private static Vector<Row> andTwoVectorRow(Vector<Row> rows1, Vector<Row> rows2)
	{
		if(rows1 == null)
			rows1 = new Vector<Row>();
		if(rows2 == null)
			rows2 = new Vector<Row>();
		
		Vector<Row> total = new Vector<Row>();
		for(int i = 0 ; i < rows1.size(); i++)
		{
			if(rows1.contains(rows1.get(i)) && rows2.contains(rows1.get(i)))
			{
				total.add(rows1.get(i));
			}
		}
		
		return total;
	}
	
	private static Vector<Row> orTwoVectorRow(Vector<Row> rows1, Vector<Row> rows2)
	{
		if(rows1 == null)
			rows1 = new Vector<Row>();
		if(rows2 == null)
			rows2 = new Vector<Row>();
		
		for(int i = 0 ; i < rows1.size(); i++)
			if(!rows2.contains(rows1.get(i)))
				rows2.add(rows1.get(i));
		
		if(rows1.size() > rows2.size())
		{
			return rows1;
		}
		
		return rows2;
	}
	
	private static Vector<Row> filterRowForOneCondition(Vector<Field> fields, Vector<Row> rows, String condition)
	{
		String[] opers = Condition.getOperandsAndOperator(condition);
		if(opers == null)
			return null;
		
		String leftOperand = opers[0];
		String rightOperand = opers[2];
		String operator = opers[1];
		Vector<Row> filterRows = (Vector<Row>) rows.clone();
		
		for(int i = 0 ; i < fields.size(); i++)
		{
			if(fields.get(i).get_Name().equals(leftOperand))
			{
				int dataType = fields.get(i).get_Type();				
				for(int j = 0 ; j < rows.size(); j++)
				{					
					switch(operator)
					{
					case ">":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name())));
								int right = Integer.parseInt(rightOperand);
								if(rowValue <= right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							
							
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) <= 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					case "<":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name())));
								int right = Integer.parseInt(rightOperand);
								if(rowValue >= right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) >= 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					case ">=":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(value);
							
								int right = Integer.parseInt(rightOperand);
								if(rowValue < right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) < 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					case "<=":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name())));
								int right = Integer.parseInt(rightOperand);
								if(rowValue > right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) > 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					case "=":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name())));
								int right = Integer.parseInt(rightOperand);
								if(rowValue != right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) != 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					case "!=":
						if(dataType == 0)
						{
							String value = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));							
							if(!value.equals("null"))
							{
								int rowValue = Integer.parseInt(String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name())));
								int right = Integer.parseInt(rightOperand);
								if(rowValue == right)
								{
									filterRows.remove(rows.get(j));
								}
							}
							else
							{
								filterRows.remove(rows.get(j));
							}
						}
						else
						{
							String rowValue = String.valueOf(rows.get(j).get_Fileds().get(fields.get(i).get_Name()));
							
							if(rowValue.equals("null"))
							{
								filterRows.remove(rows.get(j));
							}
							else if(rowValue.compareTo(rightOperand) == 0)
							{
								filterRows.remove(rows.get(j));
							}
						}
						break;
					}					
				}
			}
		}
		
		return filterRows;
	}
}
